package com.sangmo.fts.common.authority.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.data.entity.Entity;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.plugin.dataview.crud.service.JpaViewService;
import com.sangmo.fts.common.authority.AuthorityFilterChain;
import com.sangmo.fts.common.authority.EntityContext;
import com.sangmo.fts.common.authority.Rights;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;

@Transactional
public abstract class AuthorityEntityService<T extends Entity> extends JpaViewService<T> {
    protected Class<T> entityClass;
    public Class<T> getEntityClass()
    {
        if (null == entityClass)
        {
            entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return entityClass;
    }

    private void checkAuthority(Long id, int right) {
        boolean allowed = AuthorityFilterChain.getInstance().doObjectFilters(new EntityContext(getEntityClass(), (Long)id), right);
        if (!allowed) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.authority.resource.noright");
        }
    }

    private void checkCreateAuthority(Entity entity, int right) {
        boolean allowed = AuthorityFilterChain.getInstance().doCreateObjectFilters(entity, right);
        if (!allowed) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.authority.resource.noright");
        }
    }

    @Override
    public T find(Serializable id) {
        this.checkAuthority((Long)id, Rights.READ);
        T entity = super.find(id);
        return entity;
    }

    @Override
    public T get(Serializable id) {
        this.checkAuthority((Long)id, Rights.READ);
        T entity = super.get(id);
        return entity;
    }

    @Override
    public void delete(T entity) {
        this.checkAuthority((Long)entity.getId(), Rights.REMOVE);
        super.delete(entity);
    }

    @Override
    public PageResult<T> search(PageSearch ps) {
        return super.search(ps, AuthorityFilterChain.createModifier(Rights.READ));
    }

    @Override
    public T createWithEntity(T entity, Object bo) {
        this.checkCreateAuthority(entity, Rights.CREATE);
        return super.createWithEntity(entity, bo);
    }

    @Override
    public T updateWithEntity(T entity, Object bo) {
        this.checkAuthority((Long)entity.getId(), Rights.WRITE);
        return super.updateWithEntity(entity, bo);
    }
}
